home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir37 / ms_sh23s.zip / SRC / SYSTEM.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  49KB  |  2,345 lines

  1. /* MS-DOS System Function with Swaping - system (3C)
  2.  *
  3.  * MS-DOS System - Copyright (c) 1990,1,2 Data Logic Limited.
  4.  *
  5.  * This code is subject to the following copyright restrictions:
  6.  *
  7.  * 1.  Redistribution and use in source and binary forms are permitted
  8.  *     provided that the above copyright notice is duplicated in the
  9.  *     source form.
  10.  *
  11.  * Author:
  12.  *    Ian Stewartson
  13.  *    Data Logic, Queens House, Greenhill Way
  14.  *    Harrow, Middlesex  HA1 1YR, UK.
  15.  *    istewart@datlog.co.uk or ukc!datlog!istewart
  16.  *
  17.  *    $Header: /usr/users/istewart/shell/sh2.3/Release/RCS/system.c,v 2.4 1993/08/25 16:04:22 istewart Exp $
  18.  *
  19.  *    $Log: system.c,v $
  20.  *    Revision 2.4  1993/08/25  16:04:22  istewart
  21.  *    Add support for new options
  22.  *
  23.  *    Revision 2.3  1993/06/14  10:59:58  istewart
  24.  *    More changes for 223 beta
  25.  *
  26.  *    Revision 2.2  1993/06/02  09:52:35  istewart
  27.  *    Beta 223 Updates - see Notes file
  28.  *
  29.  *    Revision 2.1  1993/01/26  18:35:36  istewart
  30.  *    Fix OS2 version bug (missing semi-colon).
  31.  *
  32.  *    Revision 2.0  1992/05/21  16:49:54  Ian_Stewartson
  33.  *    MS-Shell 2.0 Baseline release
  34.  *
  35.  *
  36.  * MODULE DEFINITION:
  37.  *
  38.  * This is a version of the standard system(3c) library function.  The only
  39.  * difference is that it supports swapping and MS-SHELL EXTENDED_LINE
  40.  * processing.
  41.  *
  42.  * To get the OS2 version, compile with -DOS2
  43.  *
  44.  * There are four macros which can be changed:
  45.  *
  46.  * GET_ENVIRON        To get a variable value from the environment
  47.  * FAIL_ENVIRON        The result on failure
  48.  * FATAL_ERROR        Handle a fatal error message
  49.  * SHELL_SWITCH        The command switch to the SHELL.
  50.  *
  51.  * This module replaces the standard Microsoft SYSTEM (3C) call.  It should
  52.  * work with most models.  It has been tested in Large and Small model.
  53.  * When you link a program using the swapper, the swapper front end
  54.  * (swap.obj) must be the first object model on the linker command line so
  55.  * that it is located immediately after the PSP.  For example:
  56.  *
  57.  *    link swap+x1+x2+x3+system,x1;
  58.  * or
  59.  *    cl -o z1 swap.obj x1.obj x2.obj x3.obj system
  60.  *
  61.  * The location of the system object is not relevent.
  62.  */
  63.  
  64. #include <sys/types.h>
  65. #include <sys/stat.h>
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <errno.h>
  69. #include <limits.h>
  70. #include <ctype.h>
  71. #include <fcntl.h>
  72. #include <unistd.h>
  73. #include <string.h>
  74. #include <signal.h>
  75. #include <dirent.h>
  76.  
  77. #if defined (__TURBOC__)
  78. #  include <dir.h>
  79. #endif
  80.  
  81. #ifdef DL_MAKE
  82. #  include "make.h"
  83. #endif
  84.  
  85. #if defined(OS2) || defined (__OS2__)
  86. #  define INCL_DOSSESMGR
  87. #  define INCL_DOSMEMMGR
  88. #  define INCL_DOSPROCESS
  89. #  define INCL_WINSWITCHLIST
  90. #  define INCL_DOSERRORS
  91. #  include <os2.h>
  92. #else
  93. #  include <dos.h>
  94. #endif
  95.  
  96. #ifdef __OS2__
  97. #  define F_LOCAL
  98. #else
  99. #  define F_LOCAL        near
  100. #endif
  101.  
  102. #ifndef P_WAIT
  103. #  define P_WAIT    0
  104. #endif
  105.  
  106. /*
  107.  * Externals declared by the swapper
  108.  */
  109.  
  110. #if !defined(OS2) && !defined (__OS2__)
  111. extern char far        cmd_line[];    /* Command line            */
  112. extern char far        path_line[];    /* Process path            */
  113. extern unsigned int far    SW_intr;    /* interrupt pending        */
  114. extern unsigned int far    SW_Blocks;    /* Number of blocks to read    */
  115. extern int far        SW_fp;        /* File or EMS Handler        */
  116. extern unsigned int far    SW_EMsize;    /* Number of extend memory blks    */
  117. extern unsigned long far SW_EMstart;    /* Start addr of extend mem    */
  118.  
  119. #define SWAP_TO_DISK    1        /* Swap to disk            */
  120. #define SWAP_TO_Ext    2        /* Swap to extended memory    */
  121.                     /* Not recommended - no mgt    */
  122. #define SWAP_TO_EMS    3        /* Swap to EMS            */
  123. #define SWAP_TO_XMS    4        /* Swap to XMS            */
  124.  
  125. extern unsigned int far    SW_Mode;    /* Type of swapping to do    */
  126. extern unsigned int far    SW_EMSFrame;    /* EMS Frame segment        */
  127. extern bool far        SW_I23_InShell;    /* In the shell            */
  128.  
  129. /* Functions */
  130.  
  131. static void F_LOCAL    ClearSwapFile (void);
  132. extern int far        SA_spawn (char **);
  133. extern void (interrupt far *SW_I23_V) (void);    /* Int 23 address    */
  134. extern void (far    *SW_XMS_Driver) (void);    /* XMS Driver Interface    */
  135. extern int far        SW_XMS_Gversion (void);
  136. extern int far        SW_XMS_Allocate (unsigned int);
  137. extern int far        SW_XMS_Free (int);
  138. extern unsigned int far    SW_XMS_Available (void);
  139. extern void interrupt far SW_Int23 (void);    /* Int 23 New address    */
  140. extern void interrupt far SW_Int00 (void);    /* Int 00 New address    */
  141. #endif
  142.  
  143. #define FFNAME_MAX    (PATH_MAX + NAME_MAX + 3)
  144.  
  145. /*
  146.  * Convert to bool
  147.  */
  148.  
  149. #define C2bool(c)    (bool)((c) ? TRUE : FALSE)
  150.  
  151. /* Set these to the appropriate values to get environment variables.  For
  152.  * make the following values work.  Normally, getenv and (char *)NULL should
  153.  * be used.
  154.  */
  155.  
  156. #ifdef DL_MAKE
  157. #define GET_ENVIRON(p)        GetMacroValue (p)
  158. #define FAIL_ENVIRON        Nullstr
  159. #define FATAL_ERROR(a)        PrintFatalError (a)
  160. #define SHELL_SWITCH        "-ec"
  161. #define WINDOW_NAME        "DL Make"
  162. #else
  163. #define FATAL_ERROR(a)        { fputs (a, stderr); fputc ('\n', stderr); exit (1); }
  164. #define GET_ENVIRON(p)        getenv (p)
  165. #define FAIL_ENVIRON        (char *)NULL
  166. #define SHELL_SWITCH        "-c"
  167. #ifdef TEST
  168. #define WINDOW_NAME        "TEST"
  169. #else
  170. #define WINDOW_NAME
  171. #endif
  172. #endif
  173.  
  174. /* Declarations */
  175.  
  176.                 /* Open in create mode for swap file    */
  177. #define O_SMASK        (O_RDWR | O_CREAT | O_TRUNC | O_BINARY)
  178.  
  179. /*
  180.  * Result from FindLocationOfExecutable
  181.  */
  182.  
  183. #define EXTENSION_NOT_FOUND    0    /* Cannot find file        */
  184. #define EXTENSION_EXECUTABLE    1    /* OS/2 or DOS .exe or .com    */
  185.  
  186. /*
  187.  * Some MSDOS Swapper info
  188.  */
  189.  
  190. #if !defined(OS2) && !defined (__OS2__)
  191. #define CMD_LINE_MAX    127    /* Max command line length        */
  192.  
  193. /* MSDOS Memory Control Block chain structure */
  194.  
  195. #pragma pack (1)
  196. struct MCB_list    {
  197.     char        MCB_type;    /* M or Z            */
  198.     unsigned int    MCB_pid;    /* Process ID            */
  199.     unsigned int    MCB_len;    /* MCB length            */
  200. };
  201. #pragma pack ()
  202.  
  203. #define MCB_CON        'M'        /* More MCB's            */
  204. #define MCB_END        'Z'        /* Last MCB's            */
  205.  
  206. /* Swap Mode */
  207.  
  208. #define SWAP_OFF    0x0000        /* No swapping            */
  209. #define SWAP_DISK    0x0001        /* Disk only            */
  210. #define SWAP_EXTEND    0x0002        /* Extended memory        */
  211. #define SWAP_EXPAND    0x0004        /* Expanded memory        */
  212.  
  213. static int    Swap_Mode = (SWAP_DISK | SWAP_EXPAND | SWAP_EXTEND);
  214. static char    *NoSwapFiles = "No Swap files";
  215. static char    *MS_emsg = "WARNING - %s Error (%x)";
  216. static char    *MS_Space = "WARNING - %s out of space";
  217. static char    *SwapFailed = "%s swap failed (%x)";
  218. static char    *Swap_File = (char *)NULL;    /* Swap file    */
  219. #endif
  220.  
  221. static char    *Extend_file = (char *)NULL;
  222.  
  223. #if defined (OS2) || defined (__OS2__)
  224.  
  225. #define CMD_LINE_MAX        16000
  226. #define EXTENSION_COUNT        2
  227. static char    *Extensions [] = { "", ".exe"};
  228. static char    path_line[FFNAME_MAX];    /* Execution path        */
  229. static char    FailName[NAME_MAX + PATH_MAX + 3];
  230.  
  231. #else
  232.  
  233. #define EXTENSION_COUNT        3
  234. static char    *Extensions [] = { "", ".exe", ".com"};
  235.  
  236. #endif
  237.  
  238. /*
  239.  * Word List structure
  240.  */
  241.  
  242. typedef struct wdblock {
  243.     short    w_bsize;
  244.     short    w_nword;
  245.     char    *w_words[1];
  246. } Word_B;
  247.  
  248. /*
  249.  * Extract field from a line
  250.  */
  251.  
  252. typedef struct Fields {
  253.     FILE    *FP;            /* File handler            */
  254.     char    *Line;            /* Line buffer            */
  255.     int        LineLength;        /* Line Length            */
  256.     Word_B    *Fields;    /* ptr to the start of fields    */
  257. } LineFields;
  258.  
  259. /*
  260.  * Program type
  261.  */
  262.  
  263. static struct ExecutableProcessing {
  264.     char        *Name;
  265.     unsigned int    Flags;
  266.     unsigned char    FieldSep;
  267. } ExecProcessingMode;
  268.  
  269. /* Flags set a bit to indicate program mode */
  270.  
  271. #define EP_NONE        0x000        /* Use PSP command line        */
  272. #define EP_DOSMODE    0x001        /* Use DOS mode extended line    */
  273. #define EP_UNIXMODE    0x002        /* Use UNIX mode extended line    */
  274. #define EP_NOEXPAND    0x004        /* Use -f for this command    */
  275. #define EP_ENVIRON    0x008        /* Use environ for variable    */
  276. #define EP_NOSWAP    0x010        /* Do not swap for this command    */
  277. #define EP_COMSPEC    0x020        /* Special for .bat files    */
  278. #define EP_EXPORT    0x040        /* Use -m for this command    */
  279. #define EP_CONVERT    0x080        /* Use conversion        */
  280. #define EP_NOWORDS    0x100        /* Do word expansion        */
  281. #define EP_NOQUOTE    0x200        /* No quote protection        */
  282.  
  283. /*
  284.  * Missing errno values
  285.  */
  286.  
  287. #ifndef EIO
  288. #  define EIO        105    /* I/O error                */
  289. #endif
  290.  
  291. #ifndef E2BIG
  292. #  define E2BIG        107    /* Arg list too long            */
  293. #endif
  294.  
  295. #ifndef ENOTDIR
  296. #  define ENOTDIR    120    /* Not a directory            */
  297. #endif
  298.  
  299. /*
  300.  * Common fields in EXTENDED_LINE file
  301.  */
  302.  
  303. #define COMMON_FIELD_COUNT    5
  304.  
  305. static struct CommonFields {
  306.     char        *Name;
  307.     unsigned int    Flag;
  308. } CommonFields [] = {
  309.     { "switch",        EP_CONVERT },
  310.     { "export",        EP_EXPORT },
  311.     { "noswap",        EP_NOSWAP },
  312.     { "noquotes",    EP_NOQUOTE }
  313. };
  314.  
  315. /*
  316.  * Functions
  317.  */
  318.  
  319. #if !defined(OS2) && !defined (__OS2__)
  320. static bool F_LOCAL    Get_XMS_Driver (void);
  321. static bool F_LOCAL    Get_EMS_Driver (void);
  322. static bool F_LOCAL    EMS_error (char *, int);
  323. static bool F_LOCAL    XMS_error (char *, int);
  324. static int F_LOCAL    XMS_Close (void);
  325. static int F_LOCAL    EMS_Close (void);
  326. static int F_LOCAL    SwapToDiskError (int, char *);
  327. static int F_LOCAL    SwapToMemory (int);
  328. static void F_LOCAL    SetUpSwapper (void);
  329. #endif
  330.  
  331. static void F_LOCAL    S_getcwd (char *, int);
  332. static int F_LOCAL    CountDoubleQuotes (char *);
  333. static bool F_LOCAL    IsValidVariableName (char *);
  334. static int F_LOCAL    CountNumberArguments (char **);
  335. static bool F_LOCAL    ConvertNumericValue (char *, long *, int);
  336. static bool F_LOCAL    CheckParameterLength (char **);
  337. static int F_LOCAL    WordBlockSize (Word_B *);
  338. static Word_B * F_LOCAL AddWordToBlock (char *, Word_B *);
  339. static void F_LOCAL    ClearExtendedLineFile (void);
  340. static int F_LOCAL    ExecuteProgram (char *, char **);
  341. static int F_LOCAL    FindLocationOfExecutable (char *, char *);
  342. static char * F_LOCAL    GenerateTemporaryFileName (void);
  343. static char * F_LOCAL    BuildNextFullPathName (char *, char *, char *);
  344. static void F_LOCAL    CheckProgramMode (char *);
  345. static unsigned int F_LOCAL CheckForCommonOptions (LineFields *, int);
  346. static void F_LOCAL    SetCurrentDrive (unsigned int);
  347. static int F_LOCAL    SpawnProcess (void);
  348. static int F_LOCAL    BuildCommandLine (char *, char **);
  349. static char * F_LOCAL    GenerateFullExecutablePath (char *);
  350. static bool F_LOCAL    WriteToExtendedFile (FILE *, char *);
  351. static size_t F_LOCAL    WhiteSpaceLength (char *, bool *);
  352. static int F_LOCAL    StartTheProcess (char *, char **);
  353. static char ** F_LOCAL    ProcessSpaceInParameters (char **);
  354. static void F_LOCAL    ConvertPathToFormat (char *);
  355. static char * F_LOCAL    BuildOS2String (char **, char);
  356. static int        ExtractFieldsFromLine (LineFields *);
  357. static Word_B * F_LOCAL SplitString (char *, Word_B *);
  358. #if defined(OS2) || defined (__OS2__)
  359. static void F_LOCAL    SetWindowName (void);
  360. static int F_LOCAL    OS2_DosExecProgram (char *, char **);
  361. static char * F_LOCAL    InsertCharacterAtStart (char *);
  362. #endif
  363.  
  364. #if defined(M_I86LM)
  365. #define FAR_strcpy    strcpy
  366. #define FAR_memcpy    memcpy
  367. #define FAR_memcmp    memcmp
  368. #else
  369. #define FAR_strcpy    _fstrcpy
  370. #define FAR_memcpy    _fmemcpy
  371. #define FAR_memcmp    _fmemcmp
  372. #endif
  373.  
  374.  
  375. /*
  376.  * Test program
  377.  */
  378.  
  379. #ifdef TEST
  380. int main (int argc, char **argv)
  381. {
  382.     int        i;
  383.  
  384.     for (i = 1; i < argc; i++)
  385.     printf ("Result = %d\n", system (argv[i]));
  386.  
  387.     return 0;
  388. }
  389. #endif
  390.  
  391. /*
  392.  * System function with swapping
  393.  */
  394.  
  395. int        system (char const *arg2)
  396. {
  397.     char    *argv[4];
  398.     char    *ep;
  399.     int        res, serrno, len;
  400.     char    p_name[PATH_MAX + NAME_MAX + 3];
  401.     char    cdirectory[PATH_MAX + 4];    /* Current directory    */
  402.     char    *SaveEV = (char *)NULL;
  403.     bool    UsedComSpec = FALSE;
  404.  
  405. /* Set up argument array */
  406.  
  407.     argv[1] = SHELL_SWITCH;
  408.  
  409.     if ((argv[0] = GET_ENVIRON ("SHELL")) == FAIL_ENVIRON)
  410.     {
  411.     argv[0] = GET_ENVIRON ("COMSPEC");
  412.     argv[1] = "/c";
  413.     UsedComSpec = TRUE;
  414.     }
  415.  
  416.     if (argv[0] == FAIL_ENVIRON)
  417.     FATAL_ERROR ("No Shell available");
  418.  
  419.     argv[2] = (char *)arg2;
  420.     argv[3] = (char *)NULL;
  421.  
  422. /* Check to see if the file exists.  First check for command.com to use /
  423.  * instead of -
  424.  */
  425.  
  426.     if ((ep = strrchr (argv[0], '/')) == (char *)NULL)
  427.     ep = argv[0];
  428.  
  429.     else
  430.     ++ep;
  431.  
  432. /* Check the program mode */
  433.  
  434.     CheckProgramMode (*argv);
  435.  
  436. /* Check for command.com */
  437.  
  438. #if !defined(OS2) && !defined (__OS2__)
  439.     if (!stricmp (ep, "command.com") || !stricmp (ep, "command"))
  440.     {
  441.     union REGS    r;
  442.  
  443.     r.x.ax = 0x3700;
  444.     intdos (&r, &r);
  445.  
  446.     if ((r.h.al == 0) && (_osmajor < 4))
  447.         *argv[1] = (char)(r.h.dl);
  448.  
  449.     if (ExecProcessingMode.Flags & EP_CONVERT)
  450.         ExecProcessingMode.Flags |= EP_COMSPEC;
  451.     }
  452. #endif
  453.  
  454. /* If we used COMSPEC, default to NOQUOTES */
  455.  
  456.     if (UsedComSpec)
  457.     ExecProcessingMode.Flags |= EP_NOQUOTE;
  458.  
  459. /* Convert arguments.  If this is COMSPEC for a batch file command, skip over
  460.  * the first switch
  461.  */
  462.  
  463.     if (ExecProcessingMode.Flags & EP_COMSPEC)
  464.     len = 2;
  465.  
  466. /*
  467.  * Convert from UNIX to DOS format: Slashes to Backslashes in paths and
  468.  * dash to slash for switches
  469.  */
  470.  
  471.     if (ExecProcessingMode.Flags & EP_CONVERT)
  472.     {
  473.     while ((ep = argv[len++]) != (char *)NULL)
  474.     {
  475.         ConvertPathToFormat (ep);
  476.  
  477.         if (*ep == '-')
  478.         *ep = '/';
  479.     }
  480.     }
  481.  
  482. /* Save the current directory */
  483.  
  484.     getcwd (cdirectory, PATH_MAX + 3);
  485.  
  486. /* If pass in environment, set up environment variable */
  487.  
  488.     if (ExecProcessingMode.Flags & EP_ENVIRON)
  489.     {
  490.     if ((SaveEV = GET_ENVIRON (ExecProcessingMode.Name)) != FAIL_ENVIRON)
  491.         SaveEV = strdup (ExecProcessingMode.Name);
  492.  
  493. /* Get some space for the environment variable */
  494.  
  495.     if ((ep = malloc (strlen (ExecProcessingMode.Name) + strlen (argv[1]) +
  496.               strlen (argv[2]) + 3)) == (char *)NULL)
  497.     {
  498.         if (SaveEV != (char *)NULL)
  499.         free (SaveEV);
  500.  
  501.         free (ExecProcessingMode.Name);
  502.         return -1;
  503.     }
  504.  
  505.     sprintf (ep, "%s=%s%c%s", ExecProcessingMode.Name, argv[1],
  506.          ExecProcessingMode.FieldSep, argv[2]);
  507.  
  508. /* Stick it in the environment */
  509.  
  510.     if (putenv (ep))
  511.     {
  512.         free (ExecProcessingMode.Name);
  513.         return -1;
  514.     }
  515.  
  516.     argv[1] = ExecProcessingMode.Name;
  517.     argv[2] = (char *)NULL;
  518.     }
  519.  
  520. /* Start off on the search path for the executable file */
  521.  
  522.     res = (FindLocationOfExecutable (p_name, argv[0]))
  523.         ? ExecuteProgram (p_name, argv) : -1;
  524.  
  525.     serrno = errno;
  526.  
  527. /* Restore the current directory */
  528.  
  529.     SetCurrentDrive (tolower(*cdirectory) - 'a' + 1);
  530.  
  531.     if (chdir (&cdirectory[2]) != 0)
  532.     {
  533.     fputs ("system: WARNING - current directory reset to /\n", stderr);
  534.     chdir ("/");
  535.     }
  536.  
  537. /* Clean up environment.  Restore original value */
  538.  
  539.     if (ExecProcessingMode.Flags & EP_ENVIRON)
  540.     {
  541.     len = strlen (ExecProcessingMode.Name) + 2;
  542.  
  543.     if (SaveEV != (char *)NULL)
  544.         len += strlen (SaveEV);
  545.  
  546.     if ((ep = malloc (len)) != (char *)NULL)
  547.     {
  548.         sprintf (ep, "%s=", ExecProcessingMode.Name,
  549.              (SaveEV == (char *)NULL) ? "" : SaveEV);
  550.  
  551.         putenv (ep);
  552.     }
  553.  
  554. /* Release memory */
  555.  
  556.     if (SaveEV != (char *)NULL)
  557.         free (SaveEV);
  558.  
  559.     free (ExecProcessingMode.Name);
  560.     }
  561.  
  562.     errno = serrno;
  563.     return res;
  564. }
  565.  
  566. /*
  567.  * Exec or spawn the program ?
  568.  */
  569.  
  570. static int F_LOCAL ExecuteProgram (char    *path, char **parms)
  571. {
  572.     int            res;
  573. #if !defined (OS2) && !defined (__OS2__)
  574.     char        *ep;
  575.     unsigned int    size = 0;
  576.     int            serrno;
  577.     unsigned int    c_cur = (unsigned int)(_psp - 1);
  578.     struct MCB_list    *mp = (struct MCB_list *)((unsigned long)c_cur << 16L);
  579. #endif
  580.  
  581. /* Check to see if the file exists */
  582.  
  583.     strcpy (path_line, path);
  584.  
  585. /* Check we have access to the file */
  586.  
  587.     if (access (path_line, F_OK) != 0)
  588.     return -1;
  589.  
  590. /* Process the command line.  If no swapping, we have executed the program */
  591.  
  592.     res = BuildCommandLine (path_line, parms);
  593.  
  594. #if defined (OS2) || defined (__OS2__)
  595.     SetWindowName ();
  596.     ClearExtendedLineFile ();
  597.     return res;
  598. #else
  599.     if ((Swap_Mode == SWAP_OFF) || res)
  600.     {
  601.     ClearExtendedLineFile ();
  602.     return res;
  603.     }
  604.  
  605. /* Find the length of the swap area */
  606.  
  607.     while ((mp = (struct MCB_list *)((unsigned long)c_cur << 16L))->MCB_type
  608.         == MCB_CON)
  609.     {
  610.     if (c_cur >= 0x9ffe)
  611.         break;
  612.  
  613.     if ((mp->MCB_pid != _psp) && (mp->MCB_pid != 0) &&
  614.         (mp->MCB_type != MCB_END))
  615.     {
  616.         ClearExtendedLineFile ();
  617.         FATAL_ERROR ("Fatal: Memory chain corrupt");
  618.         return -1;
  619.     }
  620.  
  621.     c_cur += (mp->MCB_len + 1);
  622.     size += mp->MCB_len + 1;
  623.     }
  624.  
  625. /*
  626.  * Convert swap size from paragraphs to 16K blocks.
  627.  */
  628.  
  629.     if (size == 0)
  630.     size = mp->MCB_len + 1;
  631.  
  632.     SW_Blocks = (size / 0x0400) + 1;
  633.  
  634. /* OK Now we've set up the FCB's, command line and opened the swap file.
  635.  * Get some sys info for the swapper and execute my little assembler
  636.  * function to swap us out
  637.  */
  638.  
  639. /* Ok - 3 methods of swapping */
  640.  
  641. /* If expanded memory - try that */
  642.  
  643.     if ((Swap_Mode & SWAP_EXPAND) && Get_EMS_Driver ())
  644.     {
  645.     SW_Mode = 3;            /* Set Expanded memory swap    */
  646.  
  647.     if ((res = SwapToMemory (SWAP_EXPAND)) != -2)
  648.         return res;
  649.     }
  650.  
  651.     if ((Swap_Mode & SWAP_EXTEND) && Get_XMS_Driver ())
  652.     {
  653.     SW_Mode = (SW_fp == -1) ? 2 : 4;/* Set Extended memory or XMS driver */
  654.  
  655.     if ((res = SwapToMemory (SWAP_EXTEND)) != -2)
  656.         return res;
  657.  
  658.     Swap_Mode &= ~SWAP_EXTEND;
  659.     }
  660.  
  661. /* Try the disk if available */
  662.  
  663.     if (Swap_Mode & SWAP_DISK)
  664.     {
  665.     SW_fp = open ((ep = GenerateTemporaryFileName ()), O_SMASK);
  666.  
  667.     if (SW_fp < 0)
  668.         return SwapToDiskError (ENOSPC, NoSwapFiles);
  669.  
  670. /* Save the swap file name ? */
  671.  
  672.     if ((Swap_File = strdup (ep)) == (char *)NULL)
  673.         Swap_File = (char *)NULL;
  674.  
  675.     SW_Mode = 1;            /* Set Disk file swap        */
  676.  
  677. /* Execute the program */
  678.  
  679.     res = SpawnProcess ();
  680.  
  681. /* Close the extended command line file */
  682.  
  683.     ClearExtendedLineFile ();
  684.  
  685. /* Check for out of swap space */
  686.  
  687.     if (res == -2)
  688.         return SwapToDiskError (errno, "Swap file write failed");
  689.  
  690. /* Close the swap file */
  691.  
  692.     serrno = errno;
  693.     ClearSwapFile ();
  694.     errno = serrno;
  695.  
  696. /* Return the result */
  697.  
  698.     return res;
  699.     }
  700.  
  701. /* No swapping available - give up */
  702.  
  703.     ClearExtendedLineFile ();
  704.     fputs ("system: WARNING - All Swapping methods failed\n", stderr);
  705.     Swap_Mode = SWAP_OFF;
  706.     errno = ENOSPC;
  707.     return -1;
  708. #endif
  709. }
  710.  
  711. /*
  712.  * Find the location of an executable and return it's full path
  713.  * name
  714.  */
  715.  
  716. static int F_LOCAL FindLocationOfExecutable (char *FullPath, char *name)
  717. {
  718.     char    *sp;            /* Path pointers    */
  719.     char    *ep;
  720.     char    *xp;            /* In file name pointers */
  721.     char    *xp1;
  722.     int        i;
  723.  
  724. /* Scan the path for an executable */
  725.  
  726.     sp = ((strchr (name, '/') != (char *)NULL) ||
  727.       (*(name + 1) == ':')) ? ""
  728.                 : GET_ENVIRON ("PATH");
  729.  
  730.     if (sp == (char *)NULL)
  731.         sp = "";
  732.  
  733.     do
  734.     {
  735.     sp = BuildNextFullPathName (sp, name, FullPath);
  736.     ep = &FullPath[strlen (FullPath)];
  737.  
  738. /* Get start of file name */
  739.  
  740.     if ((xp1 = strrchr (FullPath, '/')) == (char *)NULL)
  741.         xp1 = FullPath;
  742.  
  743.     else
  744.         ++xp1;
  745.  
  746. /* Look up all 5 types */
  747.  
  748.     for (i = 0; i < EXTENSION_COUNT; i++)
  749.     {
  750.         strcpy (ep, Extensions[i]);
  751.  
  752.         if (access (FullPath, F_OK) == 0)
  753.         {
  754.  
  755. /* If no extension or .sh extension, check for shell script */
  756.  
  757.         if ((xp = strrchr (xp1, '.')) == (char *)NULL)
  758.             continue;
  759.  
  760.         else if (!stricmp (xp, ".exe") ||
  761.              !stricmp (xp, ".com"))
  762.             return EXTENSION_EXECUTABLE;
  763.         }
  764.     }
  765.     } while (sp != (char *)NULL);
  766.  
  767. /* Not found */
  768.  
  769.     errno = ENOENT;
  770.     return EXTENSION_NOT_FOUND;
  771. }
  772.  
  773.  
  774. /*
  775.  * Check the program type
  776.  */
  777.  
  778. static void F_LOCAL CheckProgramMode (char *Pname)
  779. {
  780.     char        *sp, *sp1;        /* Line pointers    */
  781.     int            nFields;
  782.     char        *SPname;
  783.     LineFields        LF;
  784.     long        value;
  785.  
  786. /* Set not found */
  787.  
  788.     ExecProcessingMode.Flags = EP_NONE;
  789.  
  790. /* Check not a function */
  791.  
  792.     if ((Pname == (char *)NULL) ||
  793.         ((sp = GET_ENVIRON ("EXTENDED_LINE")) == FAIL_ENVIRON))
  794.         return;
  795.  
  796. /* Get some memory for the input line and the file name */
  797.  
  798.     sp1 = ((sp1 = strrchr (Pname, '/')) == (char *)NULL) ? Pname : sp1 + 1;
  799.  
  800.     if (*(sp1 + 1) == ':')
  801.     sp1 += 2;
  802.  
  803.     if ((SPname = strdup (sp1)) == (char *)NULL)
  804.         return;
  805.  
  806.     if ((LF.Line = calloc (LF.LineLength = 200, 1)) == (char *)NULL)
  807.     {
  808.     free ((void *)SPname);
  809.     return;
  810.     }
  811.  
  812. /* Remove terminating .exe etc */
  813.  
  814.     if ((sp1 = strrchr (SPname, '.')) != (char *)NULL)
  815.         *sp1 = 0;
  816.  
  817. /* Open the file */
  818.  
  819.     if ((LF.FP = fopen (sp, "r")) == (FILE *)NULL)
  820.     {
  821.     free ((void *)LF.Line);
  822.     free ((void *)SPname);
  823.     return;
  824.     }
  825.  
  826. /* Initialise the internal buffer */
  827.  
  828.     LF.Fields = (Word_B *)NULL;
  829.  
  830. /* Scan for the file name */
  831.  
  832.     while ((nFields = ExtractFieldsFromLine (&LF)) != -1)
  833.     {
  834.         if (nFields < 2)
  835.             continue;
  836.  
  837. /* Remove terminating .exe etc */
  838.  
  839.     if ((sp = strrchr (LF.Fields->w_words[0], '.')) != (char *)NULL)
  840.         *sp = 0;
  841.  
  842.         if (stricmp (LF.Fields->w_words[0], SPname))
  843.             continue;
  844.  
  845. /* What type? */
  846.  
  847.     if (stricmp (LF.Fields->w_words[1], "unix") == 0)
  848.         ExecProcessingMode.Flags = (unsigned int )(EP_UNIXMODE |
  849.                 CheckForCommonOptions (&LF, 2));
  850.  
  851.     else if (stricmp (LF.Fields->w_words[1], "dos") == 0)
  852.         ExecProcessingMode.Flags = (unsigned int )(EP_DOSMODE |
  853.                 CheckForCommonOptions (&LF, 2));
  854.  
  855. /* Must have a valid name and we can get memory for it */
  856.  
  857.     else if ((stricmp (LF.Fields->w_words[1], "environ") == 0) &&
  858.          (nFields >= 3) &&
  859.          (!IsValidVariableName (LF.Fields->w_words[2])) &&
  860.          ((ExecProcessingMode.Name =
  861.              strdup (LF.Fields->w_words[2])) != (char *)NULL))
  862.     {
  863.         ExecProcessingMode.Flags = EP_ENVIRON;
  864.         ExecProcessingMode.FieldSep = 0;
  865.  
  866.         if ((nFields >= 4) &&
  867.         ConvertNumericValue (LF.Fields->w_words[3], &value, 0))
  868.         ExecProcessingMode.FieldSep = (unsigned char)value;
  869.  
  870.         if (!ExecProcessingMode.FieldSep)
  871.         ExecProcessingMode.FieldSep = ' ';
  872.     }
  873.  
  874.     else
  875.         ExecProcessingMode.Flags = CheckForCommonOptions (&LF, 1);
  876.  
  877.         break;
  878.     }
  879.  
  880.     fclose (LF.FP);
  881.     free ((void *)LF.Line);
  882.     free ((void *)SPname);
  883. }
  884.  
  885. /*
  886.  * Check for common fields
  887.  */
  888.  
  889. static unsigned int F_LOCAL CheckForCommonOptions (LineFields *LF, int Start)
  890. {
  891.     unsigned int    Flags = 0;
  892.     int            i, j;
  893.  
  894.     if (LF->Fields == (Word_B *)NULL)
  895.     return 0;
  896.  
  897.     for (i = Start; i < LF->Fields->w_nword; i++)
  898.     {
  899.     for (j = 0; j < COMMON_FIELD_COUNT; ++j)
  900.     {
  901.         if (!stricmp (LF->Fields->w_words[i], CommonFields[j].Name))
  902.         {
  903.         Flags |= CommonFields[j].Flag;
  904.         break;
  905.         }
  906.     }
  907.     }
  908.  
  909.     return Flags;
  910. }
  911.  
  912. /*
  913.  * Convert path format to DOS format
  914.  */
  915.  
  916. static void F_LOCAL ConvertPathToFormat (char *path)
  917. {
  918.     while ((path = strchr (path, '/')) != (char *)NULL)
  919.     *path = '\\';
  920. }
  921.  
  922. /*
  923.  * Set the current drive number and return the number of drives.
  924.  */
  925.  
  926. static void F_LOCAL SetCurrentDrive (unsigned int drive)
  927. {
  928. #if defined (OS2) || defined (__OS2__)
  929.     DosSelectDisk ((USHORT)drive);
  930.  
  931. #elif defined (__TURBOC__)
  932.    return setdisk (cdr - 1);
  933.  
  934. #else
  935.     unsigned int    ndrives;
  936.  
  937.     _dos_setdrive (drive, &ndrives);
  938. #endif
  939. }
  940.  
  941.  
  942. /*
  943.  * Clear Extended command line file
  944.  */
  945.  
  946. static void F_LOCAL ClearExtendedLineFile (void)
  947. {
  948.     if (Extend_file != (char *)NULL)
  949.     {
  950.     unlink (Extend_file);
  951.     free ((void *)Extend_file);
  952.     }
  953.  
  954.     Extend_file = (char *)NULL;
  955. }
  956.  
  957.  
  958. /* Set up command line.  If the EXTENDED_LINE variable is set, we create
  959.  * a temporary file, write the argument list (one entry per line) to the
  960.  * this file and set the command line to @<filename>.  If NOSWAPPING, we
  961.  * execute the program because I have to modify the argument line
  962.  */
  963.  
  964. static int F_LOCAL BuildCommandLine (char *path, char **argv)
  965. {
  966.     char        **pl = argv;
  967.     FILE        *fd;
  968.     bool        found;
  969.     char        *new_args[3];
  970. #if defined (OS2) || defined (__OS2__)
  971.     char        cmd_line[NAME_MAX + PATH_MAX + 3];
  972. #endif
  973.  
  974. /* Translate process name to MSDOS format */
  975.  
  976.     if (GenerateFullExecutablePath (path) == (char *)NULL)
  977.     return -1;
  978.  
  979. /* Extended command line processing */
  980.  
  981.     Extend_file = (char *)NULL;        /* Set no file        */
  982.     found = C2bool ((ExecProcessingMode.Flags & EP_UNIXMODE) ||
  983.             (ExecProcessingMode.Flags & EP_DOSMODE));
  984.  
  985. /* Set up a blank command line */
  986.  
  987.     cmd_line[0] = 0;
  988.     cmd_line[1] = 0x0d;
  989.  
  990. /* If there are no parameters, or they fit in the DOS command line
  991.  * - start the process */
  992.  
  993.     if ((*(++pl) == (char *)NULL) || CheckParameterLength (pl))
  994.     return StartTheProcess (path, argv);
  995.  
  996. /* If we can use an alternative approach - indirect files, use it */
  997.  
  998.     else if (found)
  999.     {
  1000.     char    **pl1 = pl;
  1001.  
  1002. /* Check parameters don't contain a re-direction parameter */
  1003.  
  1004.     while (*pl1 != (char *)NULL)
  1005.     {
  1006.         if (**(pl1++) == '@')
  1007.         {
  1008.         found = FALSE;
  1009.         break;
  1010.         }
  1011.     }
  1012.  
  1013. /* If we find it - create a temporary file and write the stuff */
  1014.  
  1015.     if ((found) &&
  1016.         ((fd = fopen (Extend_file = GenerateTemporaryFileName (),
  1017.               "w")) != (FILE *)NULL))
  1018.     {
  1019.         if ((Extend_file = strdup (Extend_file)) == (char *)NULL)
  1020.         Extend_file = (char *)NULL;
  1021.  
  1022. /* Copy to end of list */
  1023.  
  1024.         do
  1025.         {
  1026.         if (!WriteToExtendedFile (fd, *pl))
  1027.             return -1;
  1028.         } while (*(pl++) != (char *)NULL);
  1029.  
  1030. /* Set up cmd_line[1] to contain the filename */
  1031.  
  1032. #if defined (OS2) || defined (__OS2__)
  1033.         memset (cmd_line, 0, NAME_MAX + PATH_MAX + 3);
  1034. #else
  1035.         memset (cmd_line, 0, CMD_LINE_MAX);
  1036. #endif
  1037.         cmd_line[1] = ' ';
  1038.         cmd_line[2] = '@';
  1039.         strcpy (&cmd_line[3], Extend_file);
  1040.         cmd_line[0] = (char)(strlen (Extend_file) + 2);
  1041.  
  1042. /* Correctly terminate cmd_line in no swap mode */
  1043.  
  1044. #if !defined (OS2) && !defined (__OS2__)
  1045.         if (!(ExecProcessingMode.Flags & EP_NOSWAP) &&
  1046.         (Swap_Mode != SWAP_OFF))
  1047.         cmd_line[cmd_line[0] + 2] = 0x0d;
  1048. #endif
  1049.  
  1050. /* If the name in the file is in upper case - use \ for separators */
  1051.  
  1052.         if (ExecProcessingMode.Flags & EP_DOSMODE)
  1053.         ConvertPathToFormat (&cmd_line[2]);
  1054.  
  1055. /* OK we are ready to execute */
  1056.  
  1057. #if !defined (OS2) && !defined (__OS2__)
  1058.         if ((ExecProcessingMode.Flags & EP_NOSWAP) ||
  1059.         (Swap_Mode == SWAP_OFF))
  1060.         {
  1061. #endif
  1062.         new_args[0] = *argv;
  1063.         new_args[1] = &cmd_line[2];
  1064.         new_args[2] = (char *)NULL;
  1065.  
  1066.         return StartTheProcess (path, new_args);
  1067. #if !defined (OS2) && !defined (__OS2__)
  1068.         }
  1069.  
  1070.         else
  1071.         return 0;
  1072. #endif
  1073.     }
  1074.     }
  1075.  
  1076.     return -1;
  1077. }
  1078.  
  1079. /*
  1080.  * Set up the Window name.  Give up if it does not work.
  1081.  */
  1082.  
  1083. #if defined (OS2) || defined (__OS2__)
  1084. static void F_LOCAL SetWindowName (void)
  1085. {
  1086.     HSWITCH        hswitch;
  1087.     SWCNTRL        swctl;
  1088.  
  1089.     if (!(hswitch = WinQuerySwitchHandle (0, getpid ())))
  1090.     return;
  1091.  
  1092.     if (WinQuerySwitchEntry (hswitch, &swctl))
  1093.     return;
  1094.  
  1095.     strncpy (swctl.szSwtitle, WINDOW_NAME, sizeof (swctl.szSwtitle));
  1096.     swctl.szSwtitle[sizeof (swctl.szSwtitle) - 1] = 0;
  1097.  
  1098.     WinChangeSwitchEntry (hswitch, &swctl);
  1099. }
  1100. #endif
  1101.  
  1102.  
  1103. /*
  1104.  * Extract the next path from a string and build a new path from the
  1105.  * extracted path and a file name
  1106.  */
  1107.  
  1108. static char * F_LOCAL BuildNextFullPathName
  1109.                 (char *path_s,    /* Path string        */
  1110.                  char *file_s,    /* File name string    */
  1111.                  char *output_s)    /* Output path        */
  1112. {
  1113.     char    *s = output_s;
  1114.     int        fsize = 0;
  1115.  
  1116.     while (*path_s && (*path_s != ';') && (fsize++ < FFNAME_MAX))
  1117.     *s++ = *path_s++;
  1118.  
  1119.     if ((output_s != s) && (*(s - 1) != '/') && (fsize++ < FFNAME_MAX))
  1120.     *s++ = '/';
  1121.  
  1122.     *s = 0;
  1123.  
  1124.     if (file_s != (char *)NULL)
  1125.     strncpy (s, file_s, FFNAME_MAX - fsize);
  1126.  
  1127.     output_s[FFNAME_MAX - 1] = 0;
  1128.  
  1129.     return (*path_s ? ++path_s : (char *)NULL);
  1130. }
  1131.  
  1132. /*
  1133.  * Get and process configuration line:
  1134.  *
  1135.  * <field> = <field> <field> # comment
  1136.  *
  1137.  * return the number of fields found.
  1138.  */
  1139.  
  1140. int    ExtractFieldsFromLine (LineFields *fd)
  1141. {
  1142.     char    *cp;
  1143.     int        len;
  1144.     Word_B    *wb;
  1145.  
  1146.     if (fgets (fd->Line, fd->LineLength - 1, fd->FP) == (char *)NULL)
  1147.     {
  1148.     fclose (fd->FP);
  1149.     return -1;
  1150.     }
  1151.  
  1152. /* Remove the EOL */
  1153.  
  1154.     if ((cp = strchr (fd->Line, '\n')) != (char *)NULL)
  1155.     *cp = 0;
  1156.  
  1157. /* Remove the comments at end */
  1158.  
  1159.     if ((cp = strchr (fd->Line, '#')) != (char *)NULL)
  1160.     *cp = 0;
  1161.  
  1162. /* Extract the fields */
  1163.  
  1164.     if (fd->Fields != (Word_B *)NULL)
  1165.     fd->Fields->w_nword = 0;
  1166.  
  1167.     fd->Fields = SplitString (fd->Line, fd->Fields);
  1168.  
  1169.     if (WordBlockSize (fd->Fields) < 2)
  1170.     return 1;
  1171.  
  1172. /* Check for =.  At end of first field? */
  1173.  
  1174.     wb = fd->Fields;
  1175.     len = strlen (wb->w_words[0]) - 1;
  1176.  
  1177.     if (wb->w_words[0][len] == '=')
  1178.     wb->w_words[0][len] = 0;
  1179.  
  1180. /* Check second field for just being equals */
  1181.  
  1182.     else if (wb->w_nword < 3)
  1183.     wb->w_nword = 1;
  1184.  
  1185.     if (strcmp (wb->w_words[1], "=") == 0)
  1186.     {
  1187.     (wb->w_nword)--;
  1188.     memcpy (wb->w_words + 1, wb->w_words + 2,
  1189.         (wb->w_nword - 1) * sizeof (void *));
  1190.     }
  1191.  
  1192. /* Check the third field for starting with an equals */
  1193.  
  1194.     else if (*(wb->w_words[2]) == '=')
  1195.     strcpy (wb->w_words[2], wb->w_words[2] + 1);
  1196.  
  1197.     else
  1198.     wb->w_nword = 1;
  1199.  
  1200.     return wb->w_nword;
  1201. }
  1202.  
  1203. /*
  1204.  * Split the string up into words
  1205.  */
  1206.  
  1207. static Word_B * F_LOCAL SplitString (char *string, Word_B *wb)
  1208. {
  1209.     while (*string)
  1210.     {
  1211.     while (isspace (*string))
  1212.         *(string++) = 0;
  1213.  
  1214.     if (*string)
  1215.         wb = AddWordToBlock (string, wb);
  1216.  
  1217.     while (!isspace (*string) && *string)
  1218.         ++string;
  1219.     }
  1220.  
  1221.     return wb;
  1222. }
  1223.  
  1224. /*
  1225.  * Generate a temporary filename
  1226.  */
  1227.  
  1228. static char * F_LOCAL GenerateTemporaryFileName (void)
  1229. {
  1230.     static char    tmpfile[FFNAME_MAX];
  1231.     char    *tmpdir;    /* Points to directory prefix of pipe    */
  1232.     static int    temp_count = 0;
  1233.     char    *sep = "/";
  1234.  
  1235. /* Find out where we should put temporary files */
  1236.  
  1237.     if (((tmpdir = GET_ENVIRON ("TMP")) == FAIL_ENVIRON) &&
  1238.     ((tmpdir = GET_ENVIRON ("HOME")) == FAIL_ENVIRON) &&
  1239.     ((tmpdir = GET_ENVIRON ("TMPDIR")) == FAIL_ENVIRON))
  1240.     tmpdir = ".";
  1241.  
  1242.     if (strchr ("/\\", tmpdir[strlen (tmpdir) - 1]) != (char *)NULL)
  1243.     sep = "";
  1244.  
  1245. /* Get a unique temporary file name */
  1246.  
  1247.     while (1)
  1248.     {
  1249.     sprintf (tmpfile, "%s%ssht%.5u.tmp", tmpdir, sep, temp_count++);
  1250.  
  1251.     if (access (tmpfile, F_OK) != 0)
  1252.         break;
  1253.     }
  1254.  
  1255.     return tmpfile;
  1256. }
  1257.  
  1258. /*
  1259.  * Write a command string to the extended file
  1260.  */
  1261.  
  1262. static bool F_LOCAL WriteToExtendedFile (FILE *fd, char *string)
  1263. {
  1264.     char    *sp = string;
  1265.     char    *cp = string;
  1266.     bool    WriteOk = TRUE;
  1267.  
  1268.     if (string == (char *)NULL)
  1269.     {
  1270.     if (fclose (fd) != EOF)
  1271.         return TRUE;
  1272.  
  1273.     WriteOk = FALSE;
  1274.     }
  1275.  
  1276.     else if (strlen (string))
  1277.     {
  1278.  
  1279. /* Write the string, converting newlines to backslash newline */
  1280.  
  1281.     while (WriteOk && (cp != (char *)NULL))
  1282.     {
  1283.         if ((cp = strchr (sp, '\n')) != (char *)NULL)
  1284.         *cp = 0;
  1285.  
  1286.         if (fputs (sp, fd) == EOF)
  1287.         WriteOk = FALSE;
  1288.  
  1289.         else if (cp != (char *)NULL)
  1290.         WriteOk = C2bool (fputs ("\\\n", fd) != EOF);
  1291.  
  1292.         sp = cp + 1;
  1293.     }
  1294.     }
  1295.  
  1296.     if (WriteOk && (fputc ('\n', fd) != EOF))
  1297.     return TRUE;
  1298.  
  1299.     fclose (fd);
  1300.     ClearExtendedLineFile ();
  1301.     errno = ENOSPC;
  1302.     return FALSE;
  1303. }
  1304.  
  1305. /*
  1306.  * Convert the executable path to the full path name
  1307.  */
  1308.  
  1309. static char * F_LOCAL GenerateFullExecutablePath (char *path)
  1310. {
  1311.     char        cpath[PATH_MAX + 6];
  1312.     char        npath[PATH_MAX + NAME_MAX + 6];
  1313.     char        n1path[PATH_MAX + 6];
  1314.     char        *p;
  1315.     int            drive;
  1316.  
  1317. /* Get path in DOS format */
  1318.  
  1319.     ConvertPathToFormat (path);
  1320.  
  1321. #if defined (OS2) || defined (__OS2__)
  1322.     if (!IsHPFSFileSystem (path))
  1323.     strupr (path);
  1324. #else
  1325.     strupr (path);
  1326. #endif
  1327.  
  1328. /* Get the current path */
  1329.  
  1330.     getcwd (cpath, PATH_MAX + 3);
  1331.     strcpy (npath, cpath);
  1332.  
  1333. /* In current directory ? */
  1334.  
  1335.     if ((p = strrchr (path, '\\')) == (char *)NULL)
  1336.     {
  1337.      p = path;
  1338.  
  1339. /* Check for a:program case */
  1340.  
  1341.      if (*(p + 1) == ':')
  1342.      {
  1343.         p += 2;
  1344.  
  1345. /* Get the path of the other drive */
  1346.  
  1347.        S_getcwd (npath, tolower (*path) - 'a' + 1);
  1348.      }
  1349.     }
  1350.  
  1351. /* In root directory */
  1352.  
  1353.     else if ((p - path) == 0)
  1354.     {
  1355.     ++p;
  1356.     strcpy (npath, "x:\\");
  1357.     *npath = *path;
  1358.     *npath = *cpath;
  1359.     }
  1360.  
  1361.     else if (((p - path) == 2) && (*(path + 1) == ':'))
  1362.     {
  1363.     ++p;
  1364.     strcpy (npath, "x:\\");
  1365.     *npath = *path;
  1366.     }
  1367.  
  1368. /* Find the directory */
  1369.  
  1370.     else
  1371.     {
  1372.     *(p++) = 0;
  1373.  
  1374. /* Change to the directory containing the executable */
  1375.  
  1376.     drive = (*(path + 1) == ':') ? tolower (*path) - 'a' + 1
  1377. #if defined (OS2) || defined (__OS2__)
  1378.                         : _getdrive ();
  1379. #else
  1380.                         : 0;
  1381. #endif
  1382.  
  1383. /* Save the current directory on this drive */
  1384.  
  1385.     S_getcwd (n1path, drive);
  1386.  
  1387. /* Find the directory we want */
  1388.  
  1389.     if (chdir (path) < 0)
  1390.         return (char *)NULL;
  1391.  
  1392.     S_getcwd (npath, drive);        /* Save its full name */
  1393.     chdir (n1path);                /* Restore the original */
  1394.  
  1395. /* Restore our original directory */
  1396.  
  1397.     if (chdir (cpath) < 0)
  1398.         return (char *)NULL;
  1399.     }
  1400.  
  1401.     if (npath[strlen (npath) - 1] != '\\')
  1402.     strcat (npath, "\\");
  1403.  
  1404.     strcat (npath, p);
  1405.     return strcpy (path, npath);
  1406. }
  1407.  
  1408. /*
  1409.  * Execute or spawn the process
  1410.  */
  1411.  
  1412. static int F_LOCAL StartTheProcess (char *path, char **argv)
  1413. {
  1414. #if !defined (OS2) && !defined (__OS2__)
  1415.     return ((ExecProcessingMode.Flags & EP_NOSWAP) || (Swap_Mode == SWAP_OFF))
  1416.         ? spawnv (P_WAIT, path, ProcessSpaceInParameters (argv))
  1417.         : 0;
  1418. #else
  1419.     return OS2_DosExecProgram (path, argv);
  1420. #endif
  1421. }
  1422.  
  1423.  
  1424. /*
  1425.  * Special OS/2 processing for execve and spawnv
  1426.  */
  1427.  
  1428. #if defined (OS2) || defined (__OS2__)
  1429. static int F_LOCAL OS2_DosExecProgram (char *Program, char **argv)
  1430. {
  1431. #  if defined (__OS2__)
  1432.     APIRET        ErrorCode;
  1433. #  else
  1434.     USHORT        ErrorCode;
  1435. #  endif
  1436.     void        (*sig_int)();        /* Interrupt signal    */
  1437.     RESULTCODES        rescResults;
  1438.     PID            pidProcess;
  1439.     PID            pidWait;
  1440.     char        *OS2Environment;
  1441.     char        *OS2Arguments;
  1442.     char        **SavedArgs;
  1443.     int            argc;
  1444.  
  1445. /* Set the error module to null */
  1446.  
  1447.     *FailName = 0;
  1448.  
  1449.  
  1450. /* Build OS/2 argument string
  1451.  *
  1452.  * 1.  Count the number of arguments.
  1453.  * 2.  Add 2 for: 1 - NULL; 2 - argv[0]; 3 - the stringed arguments
  1454.  * 3.  save copy of arguments at offset 2.
  1455.  * 4.  On original argv, process white space and convert to OS2 Argument string.
  1456.  * 5.  Set up program name at offset 2 as ~argv
  1457.  * 6.  Convert zero length args to "~" and args beginning with ~ to ~~
  1458.  * 7.  Build OS2 Argument string (at last).
  1459.  */
  1460.  
  1461.     argc = CountNumberArguments (argv);
  1462.  
  1463.     if ((SavedArgs = (char **)malloc ((argc + 3) * sizeof (char *)))
  1464.                == (char **)NULL)
  1465.     return -1;
  1466.  
  1467.     memcpy (SavedArgs + 2, argv, (argc + 1) * sizeof (char *));
  1468.  
  1469. /* Set program name at Offset 0 */
  1470.  
  1471.     SavedArgs[0] = *argv;
  1472.  
  1473. /* Build OS2 Argument string in Offset 1 */
  1474.  
  1475.     if ((SavedArgs[1] = BuildOS2String (ProcessSpaceInParameters (&argv[1]),
  1476.                     ' ')) == (char *)NULL)
  1477.     return -1;
  1478.  
  1479. /* Set up the new arg 2 - ~ + programname */
  1480.  
  1481.     if ((SavedArgs[2] = InsertCharacterAtStart (*argv)) == (char *)NULL)
  1482.     return -1;
  1483.  
  1484. /* Convert zero length args and args starting with a ~ */
  1485.  
  1486.     for (argc = 3; SavedArgs[argc] != (char *)NULL; argc++)
  1487.     {
  1488.     if (strlen (SavedArgs[argc]) == 0)
  1489.         SavedArgs[argc] = "~";
  1490.  
  1491.     else if ((*SavedArgs[argc] == '~') &&
  1492.          ((SavedArgs[argc] = InsertCharacterAtStart (SavedArgs[argc]))
  1493.             == (char *)NULL))
  1494.         return -1;
  1495.     }
  1496.  
  1497. /* Build the full argument list */
  1498.  
  1499.     if ((OS2Arguments = BuildOS2String (SavedArgs, 0)) == (char *)NULL)
  1500.     return -1;
  1501.  
  1502. /* Build OS/2 environment string */
  1503.  
  1504.     if ((OS2Environment = BuildOS2String (environ, 0)) == (char *)NULL)
  1505.     return -1;
  1506.  
  1507. /* Change signal handling */
  1508.  
  1509.     sig_int = signal (SIGINT, SIG_DFL);
  1510.  
  1511. /* Exec it */
  1512.  
  1513.     ErrorCode = DosExecPgm (FailName, sizeof (FailName), EXEC_ASYNCRESULT,
  1514.                 OS2Arguments,
  1515.                 OS2Environment,
  1516.                 &rescResults, Program);
  1517.  
  1518.     signal (SIGINT, SIG_IGN);
  1519.  
  1520. /* If the process started OK, wait for it */
  1521.  
  1522.     if ((ErrorCode == NO_ERROR) || (ErrorCode == ERROR_INTERRUPT))
  1523.     {
  1524.     pidWait = rescResults.codeTerminate;
  1525.  
  1526. /* Re-try on interrupted system calls - and kill the child.  Why, because
  1527.  * sometimes the kill does not go to the child
  1528.  */
  1529.  
  1530.     while ((ErrorCode = DosCwait (DCWA_PROCESS, DCWW_WAIT,
  1531.                       &rescResults, &pidProcess,
  1532.                       pidWait)) == ERROR_INTERRUPT)
  1533.         DosKillProcess (DKP_PROCESS, pidWait);
  1534.     }
  1535.  
  1536.     signal (SIGINT, sig_int);
  1537.  
  1538. /*
  1539.  * What happened ?.  OS/2 Error - Map to UNIX errno.  Why can't people
  1540.  * write libraries right??  Or provide access at a high level.  We could
  1541.  * call _dosret if the interface did not require me to write more
  1542.  * assembler.
  1543.  */
  1544.  
  1545.     if (ErrorCode == 0)
  1546.     return rescResults.codeResult;
  1547.  
  1548.     fprintf (stderr, "system: DosExecPgm failed OS2 Error %d (%s)\n",
  1549.              ErrorCode, FailName);
  1550.  
  1551.     switch (ErrorCode)
  1552.     {
  1553.     case ERROR_NO_PROC_SLOTS:
  1554.         errno = EAGAIN;
  1555.         return -1;
  1556.  
  1557.     case ERROR_NOT_ENOUGH_MEMORY:
  1558.         errno = ENOMEM;
  1559.         return -1;
  1560.  
  1561.     case ERROR_ACCESS_DENIED:
  1562.     case ERROR_DRIVE_LOCKED:
  1563.     case ERROR_LOCK_VIOLATION:
  1564.     case ERROR_SHARING_VIOLATION:
  1565.         errno = EACCES;
  1566.         return -1;
  1567.  
  1568.     case ERROR_FILE_NOT_FOUND:
  1569.     case ERROR_PATH_NOT_FOUND:
  1570.     case ERROR_PROC_NOT_FOUND:
  1571.         errno = ENOENT;
  1572.         return -1;
  1573.  
  1574.     case ERROR_BAD_ENVIRONMENT:
  1575.     case ERROR_INVALID_DATA:
  1576.     case ERROR_INVALID_FUNCTION:
  1577.     case ERROR_INVALID_ORDINAL:
  1578.     case ERROR_INVALID_SEGMENT_NUMBER:
  1579.     case ERROR_INVALID_STACKSEG:
  1580.     case ERROR_INVALID_STARTING_CODESEG:
  1581.         errno = EINVAL;
  1582.         return -1;
  1583.  
  1584.     case ERROR_TOO_MANY_OPEN_FILES:
  1585.         errno = EMFILE;
  1586.         return -1;
  1587.  
  1588.     case ERROR_INTERRUPT:
  1589.     case ERROR_NOT_DOS_DISK:
  1590.     case ERROR_SHARING_BUFFER_EXCEEDED:
  1591.         errno = EIO;
  1592.         return -1;
  1593.  
  1594.     default:
  1595.         errno = ENOEXEC;
  1596.         return -1;
  1597.     }
  1598. }
  1599.  
  1600. /*
  1601.  * Insert character at start of string
  1602.  *
  1603.  * Return NULL or new string
  1604.  */
  1605.  
  1606. static char * F_LOCAL InsertCharacterAtStart (char *string)
  1607. {
  1608.     char    *cp;
  1609.  
  1610.     if ((cp = (char *)malloc (strlen (string) + 2)) == (char *)NULL)
  1611.     return (char *)NULL;
  1612.  
  1613.     *cp = '~';
  1614.     strcpy (cp + 1, string);
  1615.  
  1616.     return cp;
  1617. }
  1618. #endif
  1619.  
  1620. /*
  1621.  * Convert any parameters with spaces in the to start and end with double
  1622.  * quotes.
  1623.  *
  1624.  * Under OS2, the old string is NOT released.
  1625.  */
  1626.  
  1627. static char ** F_LOCAL ProcessSpaceInParameters (char **argv)
  1628. {
  1629.     char    **Start = argv;
  1630.     char    *new;
  1631.     char    *cp;
  1632.     char    *sp;
  1633.     int        Count;
  1634.  
  1635. /* If noquote set, don't even try */
  1636.  
  1637.     if (ExecProcessingMode.Flags & EP_NOQUOTE)
  1638.     return Start;
  1639.  
  1640. /* Protect parameters with TABS */
  1641.  
  1642.     while (*argv != (char *)NULL)
  1643.     {
  1644.         if ((strchr (*argv, ' ') != (char *)NULL)    ||
  1645.         (strchr (*argv, '\t') != (char *)NULL)    ||
  1646.         (strlen (*argv) == 0))
  1647.     {
  1648.  
  1649. /* Count number of Double quotes in the parameter */
  1650.  
  1651.         Count = CountDoubleQuotes (*argv);
  1652.  
  1653. /* Get some memory - give up update if out of memory */
  1654.  
  1655.         if ((new = malloc (strlen (*argv) + (Count * 2) + 3))
  1656.                  == (char *)NULL)
  1657.             return Start;
  1658.  
  1659.         *new = '"';
  1660.  
  1661. /* Escape any double quotes in the string */
  1662.  
  1663.         cp = *argv;
  1664.         sp = new + 1;
  1665.  
  1666.         while (*cp)
  1667.         {
  1668.         if (*cp == '"')
  1669.         {
  1670.             *(sp++) = '\\';
  1671.             *(sp++) = *(cp++);
  1672.         }
  1673.  
  1674.         else if (*cp != '\\')
  1675.             *(sp++) = *(cp++);
  1676.  
  1677. /* Handle escapes - count them */
  1678.  
  1679.         else
  1680.         {
  1681.             *(sp++) = *(cp++);
  1682.  
  1683.             if (*cp == '"')
  1684.             {
  1685.             *(sp++) = '\\';
  1686.             *(sp++) = '\\';
  1687.             }
  1688.  
  1689.             else if (*cp == 0)
  1690.             {
  1691.             *(sp++) = '\\';
  1692.             break;
  1693.             }
  1694.  
  1695.             *(sp++) = *(cp++);
  1696.         }
  1697.         }
  1698.  
  1699. /* Append the terminating double quotes */
  1700.  
  1701.         strcpy (sp, "\"");
  1702.         *argv = new;
  1703.     }
  1704.  
  1705. /* Check for any double quotes */
  1706.  
  1707.     else if (Count = CountDoubleQuotes (*argv))
  1708.     {
  1709.  
  1710. /* Got them - escape them */
  1711.  
  1712.         if ((new = malloc (strlen (*argv) + Count + 1)) == (char *)NULL)
  1713.             return Start;
  1714.  
  1715. /* Copy the string, escaping DoubleQuotes */
  1716.  
  1717.         cp = *argv;
  1718.         sp = new;
  1719.  
  1720.         while (*sp = *(cp++))
  1721.         {
  1722.         if (*sp == '"')
  1723.         {
  1724.             *(sp++) = '\\';
  1725.             *sp = '"';
  1726.         }
  1727.  
  1728.         sp++;
  1729.         }
  1730.  
  1731.         *argv = new;
  1732.     }
  1733.  
  1734. /* Next parameter */
  1735.  
  1736.     argv++;
  1737.     }
  1738.  
  1739.     return Start;
  1740. }
  1741.  
  1742. /*
  1743.  * Word Block Functions
  1744.  *
  1745.  * Add a new word to a Word Block or list
  1746.  */
  1747.  
  1748. static Word_B * F_LOCAL AddWordToBlock (char *wd, Word_B *wb)
  1749. {
  1750.  
  1751. /* Do we require more space ? */
  1752.  
  1753.     if ((wb == (Word_B *)NULL) || (wb->w_nword >= wb->w_bsize))
  1754.     {
  1755.     int    NewCount = (wb == (Word_B *)NULL) ? 32 : wb->w_nword * 2;
  1756.  
  1757.     if (wb == (Word_B *)NULL)
  1758.         wb = calloc (1, (NewCount * sizeof (char *)) + sizeof (Word_B));
  1759.  
  1760.     else
  1761.         wb = realloc (wb, (NewCount * sizeof (char *)) + sizeof (Word_B));
  1762.  
  1763.     if (wb == (Word_B *)NULL)
  1764.         return (Word_B *)NULL;
  1765.  
  1766.     wb->w_bsize = NewCount;
  1767.     }
  1768.  
  1769. /* Add to the list */
  1770.  
  1771.     wb->w_words[wb->w_nword++] = (void *)wd;
  1772.     return wb;
  1773. }
  1774.  
  1775. /*
  1776.  * Get the number of words in a block
  1777.  */
  1778.  
  1779. static int F_LOCAL WordBlockSize (Word_B *wb)
  1780. {
  1781.     return (wb == (Word_B *)NULL) ? 0 : wb->w_nword;
  1782. }
  1783.  
  1784. /*
  1785.  * Build the OS2 format <value>\0<value>\0 etc \0
  1786.  */
  1787.  
  1788. static char * F_LOCAL BuildOS2String (char **Array, char sep)
  1789. {
  1790.     int        i = 0;
  1791.     int        Length = 0;
  1792.     char    *Output;
  1793.     char    *sp, *cp;
  1794.  
  1795. /* Find the total data length */
  1796.  
  1797.     while ((sp = Array[i++]) != (char *)NULL)
  1798.     Length += strlen (sp) + 1;
  1799.  
  1800.     Length += 2;
  1801.  
  1802.     if ((Output = malloc (Length)) == (char *)NULL)
  1803.     return (char *)NULL;
  1804.  
  1805. /* Build the new string */
  1806.  
  1807.     i = 0;
  1808.     sp = Output;
  1809.  
  1810. /* Build the string */
  1811.  
  1812.     while ((cp = Array[i++]) != (char *)NULL)
  1813.     {
  1814.     while (*sp = *(cp++))
  1815.         ++sp;
  1816.  
  1817.     if (!sep || (Array[i] != (char *)NULL))
  1818.         *(sp++) = sep;
  1819.     }
  1820.  
  1821.     *sp = 0;
  1822.     return Output;
  1823. }
  1824.  
  1825. /*
  1826.  * Check Parameter line length
  1827.  *
  1828.  * Under OS2, we don't build the command line.  Just check it.
  1829.  */
  1830.  
  1831. static bool F_LOCAL CheckParameterLength (char **argv)
  1832. {
  1833.     int        CmdLineLength;
  1834.     char    *CommandLine;
  1835.     bool    RetVal;
  1836.     char    **SavedArgs = argv;
  1837.  
  1838. /* Check for special case.  If there are any special characters and we can
  1839.  * use UNIX mode, use it
  1840.  */
  1841.  
  1842.     if (ExecProcessingMode.Flags & EP_UNIXMODE)
  1843.     {
  1844.     while (*argv != (char *)NULL)
  1845.     {
  1846.         if (strpbrk (*(argv++), "\"'") != (char *)NULL)
  1847.         return FALSE;
  1848.     }
  1849.     }
  1850.  
  1851. /*
  1852.  * Do any parameter conversion - adding quotes or backslashes, but don't
  1853.  * update argv.
  1854.  */
  1855.  
  1856.     CmdLineLength = CountNumberArguments (argv = SavedArgs);
  1857.  
  1858.     if ((SavedArgs = (char **)malloc ((CmdLineLength + 1) * sizeof (char *)))
  1859.         == (char **)NULL)
  1860.     return FALSE;
  1861.  
  1862. /* Save a copy of the argument addresses */
  1863.  
  1864.     memcpy (SavedArgs, argv, (CmdLineLength + 1) * sizeof (char *));
  1865.  
  1866. /* Build the command line */
  1867.  
  1868.     if ((CommandLine = BuildOS2String (ProcessSpaceInParameters (SavedArgs),
  1869.                        ' ')) == (char *)NULL)
  1870.     {
  1871.     free (SavedArgs);
  1872.     return FALSE;
  1873.     }
  1874.  
  1875. /* Check command line length */
  1876.  
  1877.     if ((CmdLineLength = strlen (CommandLine)) >= CMD_LINE_MAX - 2)
  1878.     {
  1879.     errno = E2BIG;
  1880.     RetVal = FALSE;
  1881.     }
  1882.  
  1883. /* Terminate the line */
  1884.  
  1885.     else
  1886.     {
  1887. #if !defined (OS2) && !defined (__OS2__)
  1888.     strcpy (cmd_line + 1, CommandLine);
  1889.     cmd_line[CmdLineLength + 1] = 0x0d;
  1890.     cmd_line[0] = (char)CmdLineLength;
  1891. #endif
  1892.     RetVal = TRUE;
  1893.     }
  1894.  
  1895.     free (SavedArgs);
  1896.     free (CommandLine);
  1897.  
  1898.     return RetVal;
  1899. }
  1900.  
  1901. /*
  1902.  * Count DoubleQuotes
  1903.  */
  1904.  
  1905. static int F_LOCAL CountDoubleQuotes (char *string)
  1906. {
  1907.     int        Count = 0;
  1908.  
  1909.     while ((string = strchr (string, '"')) != (char *)NULL)
  1910.     {
  1911.     Count++;
  1912.     string++;
  1913.     }
  1914.  
  1915.     return Count;
  1916. }
  1917.  
  1918. /*
  1919.  * Get a valid numeric value
  1920.  */
  1921.  
  1922. static bool F_LOCAL ConvertNumericValue (char *string, long *value, int base)
  1923. {
  1924.     char    *ep;
  1925.  
  1926.     *value = strtol (string, &ep, base);
  1927.  
  1928.     return C2bool (!*ep);
  1929. }
  1930.  
  1931. /*
  1932.  * Is this a valid variable name
  1933.  */
  1934.  
  1935. static bool F_LOCAL IsValidVariableName (char *s)
  1936. {
  1937.     if (!isalpha (*s) && (*s != '_'))
  1938.     return *s;
  1939.  
  1940.     while (*s && (isalnum (*s) || (*s == '_')))
  1941.     ++s;
  1942.  
  1943.     return C2bool (*s);
  1944. }
  1945.  
  1946. /*
  1947.  * Count the number of entries in an array
  1948.  */
  1949.  
  1950. static int F_LOCAL CountNumberArguments (char **wp)
  1951. {
  1952.     int        Count = 0;
  1953.  
  1954.     while (*(wp++) != (char *)NULL)
  1955.     Count++;
  1956.  
  1957.     return Count;
  1958. }
  1959.  
  1960. /*
  1961.  * OS2 does not require swapping
  1962.  */
  1963.  
  1964. /*
  1965.  * Get the XMS Driver information
  1966.  */
  1967.  
  1968. #if !defined (OS2) && !defined (__OS2__)
  1969. static bool F_LOCAL Get_XMS_Driver (void)
  1970. {
  1971.     union REGS        or;
  1972.     struct SREGS    sr;
  1973.     unsigned int    SW_EMsize;    /* Number of extend memory blks    */
  1974.  
  1975. /* Get max Extended memory pages, and convert to 16K blocks.  If Extended
  1976.  * memory swapping disabled, set to zero
  1977.  */
  1978.  
  1979.     SW_fp = -1;                /* Set EMS/XMS handler not    */
  1980.                     /* defined            */
  1981.  
  1982. /* Is a XMS memory driver installed */
  1983.  
  1984.     or.x.ax = 0x4300;
  1985.     int86 (0x2f, &or, &or);
  1986.  
  1987.     if (or.h.al != 0x80)
  1988.     {
  1989.     or.x.ax = 0x8800;
  1990.     int86 (0x15, &or, &or);
  1991.     SW_EMsize = or.x.ax / 16;
  1992.  
  1993.     if ((SW_EMsize <= SW_Blocks) ||
  1994.          (((long)(SW_EMstart - 0x100000L) +
  1995.           ((long)(SW_Blocks - SW_EMsize) * 16L * 1024L)) < 0L))
  1996.         return XMS_error (MS_Space, 0);
  1997.  
  1998.     else
  1999.         return TRUE;
  2000.     }
  2001.  
  2002. /* Get the driver interface */
  2003.  
  2004.     or.x.ax = 0x4310;
  2005.     int86x (0x2f, &or, &or, &sr);
  2006.     SW_XMS_Driver = (void (*)())((unsigned long)(sr.es) << 16L | or.x.bx);
  2007.  
  2008. /* Support for version 3 of XMS driver */
  2009.  
  2010.     if ((SW_XMS_Gversion () & 0xff00) < 0x0200)
  2011.     return XMS_error ("WARNING - %s Version < 2", 0);
  2012.  
  2013.     else if (SW_XMS_Available () < (SW_Blocks * 16))
  2014.     return XMS_error (MS_Space, 0);
  2015.  
  2016.     else if ((SW_fp = SW_XMS_Allocate (SW_Blocks * 16)) == -1)
  2017.     return XMS_error (MS_emsg, errno);
  2018.  
  2019.     return TRUE;
  2020. }
  2021.  
  2022. /* Get the EMS Driver information */
  2023.  
  2024. static bool F_LOCAL Get_EMS_Driver (void)
  2025. {
  2026.     union REGS        or;
  2027.     struct SREGS    sr;
  2028.     char        *sp;
  2029.  
  2030. /* Set EMS/XMS handler not defined */
  2031.  
  2032.     SW_fp = -1;
  2033.  
  2034.     or.x.ax = 0x3567;
  2035.     intdosx (&or, &or, &sr);
  2036.  
  2037.     sp = (char *)((unsigned long)(sr.es) << 16L | 10L);
  2038.  
  2039. /* If not there - disable */
  2040.  
  2041.     if (memcmp ("EMMXXXX0", sp, 8) != 0)
  2042.     return EMS_error ("WARNING - %s not available", 0);
  2043.  
  2044.     or.h.ah = 0x40;            /* Check status            */
  2045.     int86 (0x67, &or, &or);
  2046.  
  2047.     if (or.h.ah != 0)
  2048.     return EMS_error (MS_emsg, or.h.ah);
  2049.  
  2050. /* Check version greater than 3.2 */
  2051.  
  2052.     or.h.ah = 0x46;
  2053.     int86 (0x67, &or, &or);
  2054.  
  2055.     if ((or.h.ah != 0) || (or.h.al < 0x32))
  2056.     return EMS_error ("WARNING - %s Version < 3.2", 0);
  2057.  
  2058. /*  get page frame address */
  2059.  
  2060.     or.h.ah = 0x41;
  2061.     int86 (0x67, &or, &or);
  2062.  
  2063.     if (or.h.ah != 0)
  2064.     return EMS_error (MS_emsg, or.h.ah);
  2065.  
  2066.     SW_EMSFrame = or.x.bx;        /* Save the page frame        */
  2067.  
  2068. /* Get the number of pages required */
  2069.  
  2070.     or.h.ah = 0x43;
  2071.     or.x.bx = SW_Blocks;
  2072.     int86 (0x67, &or, &or);
  2073.  
  2074.     if (or.h.ah == 0x088)
  2075.     return EMS_error (MS_Space, 0);
  2076.  
  2077.     if (or.h.ah != 0)
  2078.     return EMS_error (MS_emsg, or.h.ah);
  2079.  
  2080. /* Save the EMS Handler */
  2081.  
  2082.     SW_fp = or.x.dx;
  2083.  
  2084. /* save EMS page map */
  2085.  
  2086.     or.h.ah = 0x47;
  2087.     or.x.dx = SW_fp;
  2088.     int86 (0x67, &or, &or);
  2089.  
  2090.     return (or.h.ah != 0) ? EMS_error (MS_emsg, or.h.ah) : TRUE;
  2091. }
  2092.  
  2093. /* Print EMS error message */
  2094.  
  2095. static bool F_LOCAL EMS_error (char *s, int v)
  2096. {
  2097.     fputs ("system: ", stderr);
  2098.     fprintf (stderr, s, "EMS", v);
  2099.     fputc ('\n', stderr);
  2100.  
  2101.     Swap_Mode &= ~(SWAP_EXPAND);
  2102.     EMS_Close ();
  2103.     return FALSE;
  2104. }
  2105.  
  2106. /* Print XMS error message */
  2107.  
  2108. static bool F_LOCAL XMS_error (char *s, int v)
  2109. {
  2110.     fputs ("system: ", stderr);
  2111.     fprintf (stderr, s, "XMS", v);
  2112.     fputc ('\n', stderr);
  2113.  
  2114.     Swap_Mode &= ~(SWAP_EXTEND);
  2115.     XMS_Close ();
  2116.     return FALSE;
  2117. }
  2118.  
  2119. /* If the XMS handler is defined - close it */
  2120.  
  2121. static int F_LOCAL XMS_Close (void)
  2122. {
  2123.     int        res = 0;
  2124.  
  2125. /* Release XMS page */
  2126.  
  2127.     if (SW_fp != -1)
  2128.     res = SW_XMS_Free (SW_fp);
  2129.  
  2130.     SW_fp = -1;
  2131.     return res;
  2132. }
  2133.  
  2134. /* If the EMS handler is defined - close it */
  2135.  
  2136. static int F_LOCAL EMS_Close (void)
  2137. {
  2138.     union REGS        or;
  2139.     int            res = 0;
  2140.  
  2141.     if (SW_fp == -1)
  2142.     return 0;
  2143.  
  2144. /* Restore EMS page */
  2145.  
  2146.     or.h.ah = 0x48;
  2147.     or.x.dx = SW_fp;
  2148.     int86 (0x67, &or, &or);
  2149.  
  2150.     if (or.h.ah != 0)
  2151.     res = or.h.al;
  2152.  
  2153.     or.h.ah = 0x45;
  2154.     or.x.dx = SW_fp;
  2155.     int86 (0x67, &or, &or);
  2156.  
  2157.     SW_fp = -1;
  2158.     return (res) ? res : or.h.ah;
  2159. }
  2160.  
  2161. /*
  2162.  * Clear Disk swap file file
  2163.  */
  2164.  
  2165. static void F_LOCAL ClearSwapFile (void)
  2166. {
  2167.     close (SW_fp);
  2168.  
  2169.     if (Swap_File != (char *)NULL)
  2170.     {
  2171.     unlink (Swap_File);
  2172.     free ((void *)Swap_File);
  2173.     }
  2174.  
  2175.     Swap_File = (char *)NULL;
  2176. }
  2177.  
  2178. /*
  2179.  * Swap to disk error
  2180.  */
  2181.  
  2182. static int F_LOCAL SwapToDiskError (int error, char *ErrorMessage)
  2183. {
  2184. /* Clean up */
  2185.  
  2186.     ClearSwapFile ();
  2187.     Swap_Mode &= (~SWAP_DISK);
  2188.     FATAL_ERROR (ErrorMessage);
  2189.     errno = error;
  2190.     return -1;
  2191. }
  2192.  
  2193. /*
  2194.  * Swap to memory
  2195.  */
  2196.  
  2197. static int F_LOCAL    SwapToMemory (int mode)
  2198. {
  2199.     int        res;
  2200.     int        cr;
  2201.  
  2202. /* Swap and close memory handler */
  2203.  
  2204.     res = SpawnProcess ();
  2205.  
  2206.     cr = (SW_Mode != 3) ? XMS_Close () : EMS_Close ();
  2207.  
  2208.     if ((res != -2) && cr)        /* Report Close error ?        */
  2209.     {
  2210.     res = -2;
  2211.     errno = cr;
  2212.     }
  2213.  
  2214.     if (res == -2)
  2215.     (SW_Mode != 3) ? XMS_error (SwapFailed, errno)
  2216.                : EMS_error (SwapFailed, errno);
  2217.  
  2218.     else
  2219.     {
  2220.     ClearExtendedLineFile ();
  2221.     return res;
  2222.     }
  2223.  
  2224. /* Failed - disabled */
  2225.  
  2226.     Swap_Mode &= (~mode);
  2227.     return res;
  2228. }
  2229.  
  2230. /*
  2231.  * Set Interrupt handling vectors - moved from sh0.asm
  2232.  */
  2233.  
  2234. static int F_LOCAL    SpawnProcess (void)
  2235. {
  2236.     void    (interrupt far *SW_I00_V) (void);    /* Int 00 address */
  2237.     void    (interrupt far *SW_I23_V) (void);    /* Int 23 address*/
  2238.     int            res;
  2239. #if 0
  2240.     union REGS        r;
  2241.     unsigned char    Save;
  2242.  
  2243.     r.x.ax = 0x3300;
  2244.     intdos (&r, &r);
  2245.     Save = r.h.al;
  2246.     fprintf (stderr, "Break Status: %s (%u)\n", Save ? "on" : "off", Save);
  2247.  
  2248.     r.x.ax = 0x3301;
  2249.     r.h.dl = 1;
  2250.     intdos (&r, &r);
  2251.     fprintf (stderr, "Break Status: %s (%u)\n", r.h.al ? "on" : "off", r.h.al);
  2252. #endif
  2253.  
  2254. /*
  2255.  * Save current vectors
  2256.  */
  2257.  
  2258. #if defined (__TURBOC__)
  2259.     SW_I00_V = (void (far *)())getvect (0x00);
  2260.     SW_I23_V = (void (far *)())getvect (0x23);
  2261. #else
  2262.     SW_I00_V = _dos_getvect (0x00);
  2263.     SW_I23_V = _dos_getvect (0x23);
  2264. #endif
  2265.  
  2266. /*
  2267.  * Set In shell flag for Interrupt 23, and set to new interrupts
  2268.  */
  2269.  
  2270.     SW_I23_InShell = 0;
  2271.  
  2272. #if defined (__TURBOC__)
  2273.     setvect (0x23, SW_Int23);
  2274.     setvect (0x00, SW_Int00);
  2275. #else
  2276.     _dos_setvect (0x23, SW_Int23);
  2277.     _dos_setvect (0x00, SW_Int00);
  2278. #endif
  2279.  
  2280.     res = SA_spawn (environ);
  2281.  
  2282. /*
  2283.  * Restore interrupt vectors
  2284.  */
  2285.  
  2286. #if defined (__TURBOC__)
  2287.     setvect (0x00, SW_I00_V);
  2288.     setvect (0x23, SW_I23_V);
  2289. #else
  2290.     _dos_setvect (0x00, SW_I00_V);
  2291.     _dos_setvect (0x23, SW_I23_V);
  2292. #endif
  2293.  
  2294. #if 0
  2295.     r.x.ax = 0x3300;
  2296.     intdos (&r, &r);
  2297.     fprintf (stderr, "Break Status: %s (%u)\n", r.h.al ? "on" : "off", r.h.al);
  2298.     r.x.ax = 0x3301;
  2299.     r.h.dl = Save;
  2300.     intdos (&r, &r);
  2301. #endif
  2302.  
  2303. /*
  2304.  * Check for an interrupt
  2305.  */
  2306.  
  2307.     if (SW_intr)
  2308.     raise (SIGINT);
  2309.  
  2310.     return res;
  2311. }
  2312. #endif
  2313.  
  2314. /*
  2315.  * Local get current directory function to do some additional checks
  2316.  *
  2317.  * Assumes that PathName is a string of length PATH_MAX + 6.
  2318.  */
  2319.  
  2320. static void F_LOCAL S_getcwd (char *PathName, int drive)
  2321. {
  2322. #if defined (__TURBOC__)
  2323.     *(strcpy (PathName, "x:/")) = drive + 'a' - 1;
  2324. #endif
  2325.  
  2326. #if defined (__TURBOC__)
  2327.     (drive) ? getcurdir (drive, PathName + 3)
  2328.             : getcwd (PathName, PATH_MAX + 4);
  2329. #else
  2330.     (drive) ? _getdcwd (drive, PathName, PATH_MAX + 4)
  2331.             : getcwd (PathName, PATH_MAX + 4);
  2332. #endif
  2333.  
  2334.     PathName[PATH_MAX + 5] = 0;
  2335.  
  2336. /* Convert to Unix format */
  2337.  
  2338. #if (OS_VERSION != OS_DOS)
  2339.     if (!IsHPFSFileSystem (PathName))
  2340.     strlwr (PathName);
  2341. #else
  2342.     strlwr (PathName);
  2343. #endif
  2344. }
  2345.